<script setup lang="ts">
/**
 * @component CustomUpload
 * @description 这是一个基于a-upload的上传二次封装的组件，支持图片、视频、音频、附件
 *
 * @props {Promise} uploadPromise - (file: Blob) => Promise<{ url: string }>  // 希望给一个返回url链接的promise
 * @props {UploadFile[]} fileList - file列表
 * @props {Function} setFileList - (value: UploadFile[]) => void
 * @props {Function} updateUploadings - (index: number, time?: number) => void  设置上传状态
 * @props {string} type - 上传类型
 * @props {number} fileLength - 上传长度
 *
 * @example
 * <CustomUpload
 *  :uploadPromise="Promise"
 *  :fileList="fileList"
 *  :setFileList="setFileList"
 *  :updateUploadings="updateUploadings"
 *  type="image"
 *  :fileLength="1" />
 *
 * @author cx
 * @date 2024-01-19
 */
import { extractFolderNameFromLink } from '@/utils/common'
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue/es/components'
import { UploadChangeParam, UploadFile } from 'ant-design-vue/es/upload/interface'
import { UploadRequestOption } from 'ant-design-vue/es/vc-upload/interface'
const uploadInfo: { [key: string]: { title: string; msg: string; regex: RegExp; size: number } } = {
  image: {
    title: '图片',
    msg: '支持jpg/png格式10M以内',
    regex: /(jpeg|jpg|png)/i,
    size: 10
  },
  video: {
    title: '视频',
    msg: '支持mp4格式10M以内',
    regex: /(mp4)/i,
    size: 10
  },
  file: {
    title: '文件',
    msg: '支持pdf/word/excel/PPT格式50M以内',
    regex: /(pdf|doc|docx|docm|xls|xlsx|xlsm|ppt|pptx|pptm)/i,
    size: 50
  }
}
interface CustomUploadProps {
  /* 上传接口 */
  uploadPromise: (file: Blob) => Promise<{ url: string }>
  /** 上传 */
  fileList: UploadFile[]
  setFileList: (value: UploadFile[]) => void
  updateUploadings: (index: number, time?: number) => void
  type: string
  fileLength: number
}

const props = defineProps<CustomUploadProps>()
const loading = ref<boolean>(false)
const previewOpen = ref(false)
const previewFileUrl = ref()
const previewTitle = ref('')
const currentUploadInfo = computed(() => {
  return uploadInfo[props.type]
})

/** 预览 */
const handlePreview = async (file: UploadFile) => {
  previewTitle.value = extractFolderNameFromLink(file.url || file.preview || '')
  previewFileUrl.value = file.url || file.preview
  previewOpen.value = true
}

/** 关闭 */
const handleCancel = async () => {
  previewOpen.value = false
}

/** 上传图片只拿上传成功的数据 */
const handleChange = (info: UploadChangeParam) => {
  info.fileList
  props.setFileList([...info.fileList.filter((item) => item && item?.status === 'done')])
}

/**  上传图片得类型 */
const beforeUpload = async (option: UploadRequestOption) => {
  if (loading.value) return
  const file = option.file as Blob

  const fileType = file.name.substring(file.name.lastIndexOf('.') + 1)
  const { regex, msg, title, size } = currentUploadInfo.value
  if (!regex.test(fileType)) {
    message.error(msg)
    return
  }
  if (!(file.size / 1024 / 1024 < size)) {
    message.error(`${title}必须小于 ${size}MB!`)
  } else {
    loading.value = true
    // // 添加上传中状态（添加这个的原因就是想要文件上传的过程中，发送按钮不可点击）
    props.updateUploadings(1, new Date().getTime())
    const res = await props.uploadPromise(file)

    const fileList = [...props.fileList]
    fileList.push({
      status: 'done',
      uid: new Date().getTime().toString(),
      url: res.url,
      name: file.name
    })
    props.setFileList(fileList)
    // 接口请求完毕，更新加载去掉，发送按钮可点击
    props.updateUploadings(0)
    loading.value = false
  }
}
</script>

<template>
  <div>
    <a-upload
      listType="picture-card"
      :fileList="props.fileList"
      :onPreview="handlePreview"
      :onChange="handleChange"
      :customRequest="beforeUpload"
    >
      <div v-if="props.fileList.length <= props.fileLength">
        <div v-if="!loading">
          <PlusOutlined />
          <div :style="{ marginTop: 8 }">
            <p>点击上传{{ currentUploadInfo.title }} </p>
          </div>
        </div>
        <p v-else>上传中...<LoadingOutlined /></p>
      </div>
    </a-upload>
    <a-modal v-model:open="previewOpen" :title="previewTitle" :footer="null" @cancel="handleCancel">
      <img v-if="props.type === 'image'" style="height: 300px" :src="previewFileUrl" alt="" />
      <video
        v-else-if="props.type === 'video'"
        :src="previewFileUrl"
        style="width: 100%; height: 300px"
        controls
      >
        <track kind="captions" />
      </video>
    </a-modal>
  </div>
</template>
